package asia.lxq.cic.entity;

import org.springframework.http.HttpStatus;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用处理结果
 * <pre>
 *     1 默认成功状态，msg=""
 *     2 data为空时，可使用实例链式编程put(String,Object)添加Map集合
 * </pre>
 *
 * @author MuYi
 * @version 1.0
 * @date 2022/4/2 13:43
 **/
public class Result<T> implements Serializable {
    private static final int OK_CODE_VALUE = HttpStatus.OK.value();
    private static final int FIRST_ERR_CODE_VALUE = HttpStatus.BAD_REQUEST.value();

    /**
     * 是否成功、只读
     */
    private boolean success;
    /**
     * 状态码
     * <pre>
     *     以HttpStatus为主架构，原有定义不得乱用。
     *     正常返回代码为200,即HttpStatus.OK.value()
     *
     *     用户自定义错误代码需大于1000
     * </pre>
     *
     * @see org.springframework.http.HttpStatus
     */
    private int code = HttpStatus.OK.value();
    /**
     * 当data为null时为0；为Map、list、Array时，获取其长度；其他类型为1
     */
    private int count = 0;
    /**
     * 信息
     */
    private String msg;
    /**
     * 结果数据
     */
    private T data;
    /**
     * 满足查询条件的记录总数
     */
    private long total = 0;

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
        this.success = code >= OK_CODE_VALUE && code < FIRST_ERR_CODE_VALUE;

    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
        count = obtainDataCount(data);
    }

    /**
     * 根据code判断是否成功
     * <pre>
     *     code大于等于200 小于400
     * </pre>
     *
     * @return 是否
     * @see #error(String)
     */
    public boolean isSuccess() {
        return this.success;
    }

    /**
     * 根据code判断是否成功
     * <pre>
     *     code大于等于200 小于400
     * </pre>
     *
     * @return 是否
     * @see #error(String)
     */
    public boolean getSuccess() {
        return this.success;
    }

    public int getCount() {
        return count;
    }

    /**
     * 构造
     *
     * @param code 状态码
     * @param data 结果数据
     * @param msg  信息。为空且处理成功时，前台不显示
     */
    private Result(Integer code, T data, String msg) {
        init(code, data, msg);
    }

    /**
     * 构造
     *
     * @param code 状态码
     * @param data 结果数据
     * @param msg  信息。为空且处理成功时，前台不显示
     */
    private Result(StatusCode code, T data, String msg) {
        init(code.getValue(), data, msg);
    }

    private Result(StatusCode code, T data, String msg,boolean isSuccess) {
        setCode(code.getValue());
        setMsg(msg);
        setData(data);
        this.success=isSuccess;
    }

    /**
     * 构造
     *
     * @param code 状态码
     * @param data 结果数据
     * @param msg  信息。为空且处理成功时，前台不显示
     */
    private Result(HttpStatus code, T data, String msg) {
        init(code.value(), data, msg);
    }

    private void init(Integer code, T data, String msg) {
        setCode(code);
        setMsg(msg);
        setData(data);
    }

    /**
     * 初始化成功/失败新实例
     *
     * @param code 代码200、300系列一般为成功;400、500系列为失败
     * @param data 处理结果
     * @param msg  信息。为空且且处理成功时，前台可不显示
     * @return 新实例
     */
    public static <T> Result<T> build(Integer code, T data, String msg) {
        if (!isSuccessCode(code)) code = OK_CODE_VALUE;
        return new Result<T>(code, data, msg);
    }

    /**
     * 传什么就返回什
     * @param code
     * @param data
     * @param msg
     * @return
     * @param <T>
     */
    public static <T> Result<T> buildOrigin(StatusCode code, T data, String msg,boolean isSuccess) {
        return new Result<T>(code, data, msg,isSuccess);
    }

    /**
     * 初始化成功/失败新实例
     *
     * @param code 代码
     * @param data 处理结果
     * @param msg  信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> build(StatusCode code, T data, String msg) {
        return build(code.getValue(), data, msg);
    }

    /**
     * 初始化成功/失败新实例
     *
     * @param code 代码200、300系列一般为成功;400、500系列为失败
     * @param data 处理结果
     * @param msg  信息。为空且且处理成功时，前台可不显示
     * @return 新实例
     */
    public static <T> Result<T> build(HttpStatus code, T data, String msg) {
        return build(code.value(), data, msg);
    }

    /**
     * 初始化成功新实例
     * <pre>
     * Result.<Map<String, Object>>success(),可随后使用链式编程.put添加Map数据
     * </pre>
     *
     * @param msg 信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> success(String msg) {
        return build(OK_CODE_VALUE, null, msg);
    }

    /**
     * 初始化成功新实例
     * <pre>
     * Result.<Map<String, Object>>success(),可随后使用链式编程.put添加Map数据
     * </pre>
     *
     * @return 新实例
     */
    public static <T> Result<T> success() {
        return build(OK_CODE_VALUE, null, "");
    }


    /**
     * 初始化成功新实例
     *
     * @param data 处理结果
     * @param msg  信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> success(T data, String msg) {
        return build(StatusCode.OK.getValue(), data, msg);
    }

    /**
     * 初始化成功新实例
     *
     * @param data 处理结果
     * @return 新实例
     */
    public static <T> Result<T> success(T data) {
        return build(StatusCode.OK.getValue(), data, "");
    }

    /**
     * 初始化失败新实例
     *
     * @param code 代码非200、300系列时自动设置为400 BAD_REQUEST
     * @param data 处理结果
     * @param msg  信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> error(Integer code, T data, String msg) {
        if (!isSuccessCode(code)) code = FIRST_ERR_CODE_VALUE;
        return new Result<T>(code, data, msg);
    }


    /**
     * 初始化失败新实例
     *
     * @param code 代码为非200、300系列
     * @param msg  信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> error(HttpStatus code, String msg) {
        return build(code, null, msg);
    }

    /**
     * 初始化失败新实例
     *
     * @param code 代码为非OK
     * @param msg  信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> error(StatusCode code, String msg) {
        return build(code, null, msg);
    }

    /**
     * 初始化失败新实例
     * <pre>code=StatusCode.SYSTEM_ERR</pre>
     *
     * @param msg 信息。为空且处理成功时，前台不显示
     * @return 新实例
     */
    public static <T> Result<T> error(String msg) {
        return build(StatusCode.SYSTEM_ERR, null, msg);
    }

    /**
     * 初始化失败新实例
     * <pre>msg由代码定义获得</pre>
     *
     * @param code 代码应为非OK
     * @return 新实例
     */
    public static <T> Result<T> error(StatusCode code) {
        return build(code, null, code.getDesc());
    }

    /**
     * 初始化失败新实例
     * <pre>msg由代码定义获得</pre>
     *
     * @param code 代码应为非200、300系列
     * @return 新实例
     */
    public static <T> Result<T> error(HttpStatus code) {
        return build(code, null, code.getReasonPhrase());
    }

    /**
     * 判断状态是否为成功代码
     * <pre>
     *     code大于等于200 小于400
     * </pre>
     *
     * @param code 状态码
     * @return 是否
     */
    public static boolean isSuccessCode(Integer code) {
        if (code == null) return false;
        return code >= OK_CODE_VALUE && code < FIRST_ERR_CODE_VALUE;
    }

    /**
     * 如果data为Collection、Map计算data长度。否则返回0或1
     * <pre>
     *     data为null返回0，
     * </pre>
     *
     * @param data 输入
     * @return 长度
     */
    public static int obtainDataCount(Object data) {
        if (data == null) return 0;
        if (data instanceof Map) return ((Map<?, ?>) data).size();
        else if (data instanceof Collection) return ((Collection<?>) data).size();
        else return 1;
    }

    /**
     * 向data添加键值对
     * <pre>
     *     如果本实例的data不为空且不是Map<String,Object>直接返回本实例，添加无效
     * </pre>
     *
     * @param key   键名 为空直接返回本实例，否则，存在则覆盖，不存在新建
     * @param value 值
     * @return 本实例
     */
    public Result<T> put(String key, Object value) {
        if (this.data == null) this.data = (T) new HashMap<String, Object>();
        ((Map<String, Object>) this.data).put(key, value);
        count = obtainDataCount(data);
        return this;
    }

    /**
     * 向data添加键值对
     * <pre>
     *     如果本实例的data不为空且不是Map<String,Object>直接返回本实例，添加无效
     * </pre>
     *
     * @param map 值
     * @return 本实例
     */
    public Result<T> put(Map<String, Object> map) {
        if (this.data == null) this.data = (T) new HashMap<String, Object>();
        ((Map<String, Object>) this.data).putAll(map);
        count = obtainDataCount(data);
        return this;
    }

}